<template>
  <div class="video_box">
    <!-- 视频显示 -->
    <div class="videoCall_box">
      <!-- 医生显示 -->
      <div
        id="doctorVideoStream"
        v-show="VideoDisplay"
        @click="changeMainVideo"
        :class="isLocalMain ? 'big' : 'small'"
      ></div>
      <!-- 用户显示 -->
      <div
        name="userVideoStream"
        v-show="VideoDisplay"
        @click="changeMainVideo"
        :class="{'small': isLocalMain, 'big': !isLocalMain, 'isRotacion': isRotacion}"
        :style="{'transform':videoTransform,'-ms-transform':videoTransform,'-moz-transform':videoTransform,'-webkit-transform':videoTransform,'-o-transform':videoTransform}"
      ></div>
    </div>
    <p class="videoTips" v-if="isDialled">有患者向你发起视话邀请...</p>
    <div class="videoTips_box" v-if="VideoInterruption">
      <p>视频已中断。</p>
      <p>若问诊已结束,请点击右上角结束就诊按钮,结束本次问诊。</p>
      <p>若问诊未结束,请耐心等待用户再次发起问诊。</p>
    </div>
    <!-- 接听和挂断按钮 -->
    <div class="buttons" v-show="!VideoInterruption">
      <p v-show="calling">{{ formatDurationStr }}</p>
      <i
        @click="AnswerOrEnd"
        :class="{'el-icon-phone': true, 'Answer': !calling, 'Answering': calling}"
      ></i>
      <span>{{ calling ? '挂断' : '接听' }}</span>
    </div>
  </div>
</template>
<script>
// 导入腾讯云连接
import TRtcClient from "../../utils/rtc-client";
// 导入腾讯云状态
import { ACTION, VERSION } from "../../utils/trtcCustomMessageMap";
// 导入通话时间计算
import { formatDuration } from "../../utils/formatDuration";
export default {
  props: {
    videoState: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      Trtc: null,
      videoRoom: "", //房间id
      toAccount: "", //发送人
      currentConversationType: "",
      DoctorId: "",
      DoctorSig: "",
      // SDKAppID: "1400348670", // 预生产/生产
      SDKAppID: "1400340117", // 开发/测试
      isDialled: false, //是否被呼叫
      dialling: false, //是否在拨打电话中
      ready: false,
      calling: false,
      start: 0,
      hangUpTimer: 0,
      duration: 0,
      isBuy: false,
      isLocalMain: false,
      VideoInterruption: false,
      VideoDisplay: false,
      EndOfConsultationOrNot: false, //如果是false用户挂断后就不用展示病历了
      formUser: "", //当前和医生问诊的用户
      login: false,
      isRotacion: false, //是否旋转
      videoTransform: ""
    };
  },
  /**
   * 1.未接听视频业务逻辑没处理 (已完成)
   * 2.反复测试确保程序有没有问题
   * 3.接听后发送给原生的状态是未定义需要注意
   * 4.在用户发送给医生端时医生端点击了提听在画面没显示出来之前如果用户端点击了挂断按钮界面显示会异常（已处理）
   * 5.通话时间还没有计算（已处理）
   * 6.和一个用户通话中另外一个用户打过来界面显示不正常(已处理)
   * 7.通过web端发送过来的视频请求这里显示加入失败(已处理)
   * 8.正在视话中网络断开业务逻辑还没有测试
   */
  created() {
    let self = this;
    self.initListener();
    window.addEventListener("online", function() {
      self.$notify.closeAll();
      window.removeEventListener("online", () => {});
      if (!self.login) return;
      setTimeout(() => {
        location.reload();
      }, 1000);
    });
    window.addEventListener("offline", function() {
      window.removeEventListener("offline", () => {});
      if (!self.login) return;
      self.Trtc && self.Trtc.closeVideo();
      self.$notify({
        title: "连接错误",
        message: "连接已断开,请检查网络连接并刷新页面重新连接",
        duration: 0
      });
      self.lineError("error");
      self.$bus.$emit("saveUser");
    });
  },
  mounted() {
    let self = this;
    window.addEventListener("beforeunload", async e => {
      if (self.calling) {
        await self.sendVideoMessage(ACTION.VIDEO_CALL_ACTION_ERROR_HANGUP);
        window.removeEventListener("beforeunload", e => {
          // console.log("销毁了")
        });
      }
    });
    self.DoctorId = localStorage.getItem("doctorId");
    if (self.$store.state.common.DoctorId) {
      if (self.$store.state.common.DoctorSig) {
        self.DoctorId = self.$store.state.common.DoctorId;
        self.DoctorSig = self.$store.state.common.DoctorSig;
      }
    }
    if (sessionStorage.getItem("videoData")) {
      if (sessionStorage.getItem("EndOfConsultationOrNot") == "true") {
        self.lineError();
      }
    }
    self.$bus.$on("error", self.lineError);
    self.$bus.$on("LastOrder", self.LastOrder);
    self.$bus.$on("displayVideoBox", self.displayVideoBox);
  },
  watch: {
    "$store.state.common.DoctorId": function(val) {
      let self = this;
      self.DoctorId = val;
    },
    "$store.state.common.DoctorSig": function(val) {
      let self = this;
      self.DoctorSig = val;
    },
    "$store.state.common.SDKAppID": function(val) {
      let self = this;
      self.SDKAppID = val;
    },
    "$store.state.common.STATE": function(val) {
      let self = this;
      switch (val) {
        case 3:
          if (self.EndOfConsultationOrNot) {
            self.hangUp("end");
          } else if (self.isDialled) {
            self.refuse();
          }
          if (
            !sessionStorage.getItem("EndOfConsultationOrNot") ||
            !sessionStorage.getItem("LastOrder")
          ) {
            self.initDateValue();
          }
          if (sessionStorage.getItem("formUser")) {
            self.formUser = sessionStorage.getItem("formUser");
          }
          break;
      }
    },
    "$store.state.common.TIMLOING_STATE": function(val) {
      let self = this;
      switch (val) {
        case 2:
          self.loginTim();
          break;
        case 5:
          self.loginOutTim();
          break;
      }
    },
    videoState(val) {
      let self = this;
      if (val) return;
      // 当值改变了就恢复所有值为默认值
      self.initDateValue();
    }
  },
  methods: {
    LastOrder() {
      let self = this;
      self.lineError();
      sessionStorage.setItem("LastOrder", true);
      self.EndOfConsultationOrNot = true;
      sessionStorage.setItem(
        "EndOfConsultationOrNot",
        self.EndOfConsultationOrNot
      );
      self.loginTim("lastOrder");
    },
    lineError(type) {
      let self = this;
      clearTimeout(this.hangUpTimer);
      let array = [
        "isDialled",
        "dialling",
        "ready",
        "calling",
        "isBuy",
        "isLocalMain",
        "VideoInterruption",
        "VideoDisplay"
      ];
      array.forEach(item => {
        switch (item) {
          case "VideoInterruption":
            self[item] = true;
            break;
          default:
            self[item] = false;
            break;
        }
      });
    },
    // 初始化date的值
    initDateValue() {
      let self = this;
      let Array = [
        "videoRoom",
        "toAccount",
        "currentConversationType",
        "isDialled",
        "dialling",
        "ready",
        "calling",
        "start",
        "hangUpTimer",
        "duration",
        "isBuy",
        "isLocalMain",
        "VideoInterruption",
        "VideoDisplay",
        "EndOfConsultationOrNot",
        "formUser",
        "isRotacion"
      ];
      Array.forEach(item => {
        switch (typeof self[item]) {
          case "object":
            self[item] = null;
            break;
          case "number":
            self[item] = 0;
            break;
          case "boolean":
            self[item] = false;
            break;
          case "string":
            self[item] = "";
            break;
        }
      });
    },
    // 登出腾讯im
    loginOutTim() {
      let self = this;
      self.login = false;
      let promise = self.tim.logout();
      promise
        .then(function(imResponse) {
          self.$store.dispatch("GET_STATE", 2);
          self.$store.dispatch("GET_TIMLOING_STATE", 6);
          self.$store.dispatch("CHANGE_SET_SIG", "");
          localStorage.clear();
          sessionStorage.clear();
          // 返回登录页
          self.basePushFun("/login");
        })
        .catch(function(imError) {
          self.$message({
            type: "error",
            message: "登出失败"
          });
          self.$store.dispatch("GET_STATE", 3);
          self.$store.dispatch("GET_TIMLOING_STATE", 7);
        });
    },
    changeMainVideo() {
      let self = this;
      if (!self.calling) {
        return;
      }
      self.isLocalMain = !self.isLocalMain;
    },
    // 登录腾讯im
    loginTim(type) {
      console.log("---------------登录腾讯im------------------");
      let self = this;
      if (self.login) return;
      self.login = true;
      let loginOptions = {
        userID: self.DoctorId || self.$store.state.common.DoctorId,
        // 这里的userSig在后期要是用后端返回的userSig
        userSig: self.DoctorSig || self.$store.state.common.DoctorSig
      };
      self.tim
        .login(loginOptions)
        .then(() => {
          if (!type) {
            // self.$store.dispatch("GET_STATE", 3);
            self.$store.dispatch("GET_TIMLOING_STATE", 3);
          } else if (type == "lastOrder") {
            self.$store.dispatch("GET_STATE", 5);
          }
        })
        .catch(error => {
          self.$message({
            type: "error",
            message: "登录失败"
          });
          self.$store.dispatch("GET_STATE", 2);
          self.$store.dispatch("GET_TIMLOING_STATE", 4);
          setTimeout(() => {
            if (error.message == "Network Error") {
              self.$message({
                type: "error",
                message: "网络异常，请确认网络环境再刷新页面"
              });
            }
          }, 1000);
        });
    },
    // 初始化 trtc 进入房间
    async initTrtc(Option) {
      let self = this;
      self.Trtc = new TRtcClient(Option);

      await self.Trtc.createLocalStream({ audio: true, video: true })
        .then(() => {
          self.Trtc.join();
          self.ready = true;
        })
        .catch(() => {
          alert("请确认已连接摄像头和麦克风并授予可访问权限");
          self.ready = false;
        });
    },

    sendVideoMessage(action, duration = 0) {
      let self = this;
      const options = {
        roomId: this.videoRoom,
        callId: "",
        action,
        version: VERSION,
        invitedList: [],
        duration
      };

      options.invitedList.push(this.toAccount);
      const message = this.tim.createCustomMessage({
        to: this.toAccount,
        conversationType: this.currentConversationType,
        payload: {
          data: JSON.stringify(options),
          description: "",
          extension: ""
        }
      });
      this.tim.sendMessage(message);
    },

    busy(videoPayload, messageItem) {
      let self = this;
      videoPayload.action = ACTION.VIDEO_CALL_ACTION_LINE_BUSY;
      const message = self.tim.createCustomMessage({
        to: messageItem.from,
        conversationType: this.currentConversationType,
        payload: {
          data: JSON.stringify(videoPayload),
          description: "",
          extension: ""
        }
      });
      self.tim.sendMessage(message);
    },

    AnswerOrEnd() {
      let self = this;
      if (!self.calling) {
        self.accept();
      } else {
        self.hangUp();
      }
    },

    // 接听电话
    accept() {
      let self = this;
      self.$store.dispatch("GET_STATE", 4);
      self.changeState("calling", true, 1);
      self.VideoDisplay = true;
      self.EndOfConsultationOrNot = true;
      self.$bus.$emit("saveUser");
      sessionStorage.setItem(
        "EndOfConsultationOrNot",
        self.EndOfConsultationOrNot
      );
      sessionStorage.setItem("formUser", self.formUser);
      const options = {
        userId: self.DoctorId || self.$store.state.common.DoctorId,
        // 这里的userSig在后期要是用后端返回的userSig
        userSig: self.DoctorSig || self.$store.state.common.DoctorSig,
        roomId: this.videoRoom,
        sdkAppId: self.SDKAppID
      };

      self.initTrtc(options).then(() => {
        if (!self.ready) {
          self.changeState("calling", false, 2);
          this.sendVideoMessage(ACTION.VIDEO_CALL_ACTION_ERROR);
          self.$store.dispatch("GET_STATE", 3);
          self.$store.dispatch("GET_TIMLOING_STATE", 3);
          self.$emit("changeVideoState", false);
          return;
        }
        //this.sendVideoMessage(ACTION.VIDEO_CALL_ACTION_ACCEPTED);
        // 开始计时
        self.start = new Date();
        clearTimeout(this.hangUpTimer);
        this.reserDuration(0);
      });
    },

    // 拒绝电话
    refuse() {
      let self = this;
      self.VideoDisplay = false;
      self.changeState("isDialled", false, 3);
      self.sendVideoMessage(ACTION.VIDEO_CALL_ACTION_REJECT);
    },

    // 通话一段时间后某一方挂断电话
    hangUp(type) {
      let self = this;
      if (!type) {
        self.$store.dispatch("GET_STATE", 5);
      }

      self.changeState("calling", false, 4);
      self.VideoDisplay = false;
      self.VideoInterruption = true;
      self.Trtc.leave();
      self.end = new Date();
      const duration = parseInt((self.end - self.start) / 1000);
      self.sendVideoMessage(ACTION.VIDEO_CALL_ACTION_HANGUP, duration);
      clearTimeout(self.hangUpTimer);
    },
    // 通话一段时间后对方挂断电话
    isHungUp() {
      let self = this;
      self.$store.dispatch("GET_STATE", 5);
      if (self.calling) {
        self.changeState("calling", false, 5);
        self.VideoDisplay = false;
        self.Trtc.leave();
        clearTimeout(self.hangUpTimer);
      }
    },

    reserDuration(duration) {
      let self = this;
      self.duration = duration;
      self.hangUpTimer = setTimeout(() => {
        let now = new Date();
        self.reserDuration(parseInt((now - self.start) / 1000));
      }, 1000);
    },

    isJsonStr(str) {
      try {
        JSON.parse(str);
        return true;
      } catch (e) {
        return false;
      }
    },

    changeState(state, boolean, index) {
      let self = this;
      // console.log("changestate" + index);
      let stateList = ["dialling", "isDialled", "calling"];
      stateList.forEach(item => {
        this[item] = item === state ? boolean : false;
      });
      self.isBuy = stateList.some(item => this[item]);
    },

    displayVideoBox(id) {
      let self = this;
      if (id !== this.DoctorId) {
        // 显示接听界面
        self.changeState("isDialled", true, 6);
        self.$emit("changeVideoState", true);
        self.VideoInterruption = false;
      }
    },

    handleVideoMessage(messageList) {
      let self = this;
      const videoMessageList = messageList.filter(
        message =>
          message.type === this.TIM.TYPES.MSG_CUSTOM &&
          self.isJsonStr(message.payload.data)
      );

      if (videoMessageList.length == 0) return;
      const videoPayload = JSON.parse(videoMessageList[0].payload.data);
      this.currentConversationType = videoMessageList[0].conversationType;
      // 正在呼叫
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_DIALING) {
        if (
          self.isBuy ||
          (self.formUser != "" && self.formUser != videoMessageList[0].from)
        ) {
          // 电话占线
          self.busy(videoPayload, videoMessageList[0]);
          return;
        }
        self.$store.dispatch("GET_STATE", 6);
        self.videoRoom = videoPayload.room_id || videoPayload.roomId;
        self.toAccount = videoMessageList[0].from;
        if (self.formUser == "") {
          self.formUser = videoMessageList[0].from;
        }
        if (!self.EndOfConsultationOrNot) {
          self.$emit("sendPatientData", {
            id: videoMessageList[0].from,
            version: videoPayload.version,
            factoryId: videoPayload.factoryId || ""
          });
          // videoPayload.version == 5 ? self.isRotacion = true : self.isRotacion = false;
          if (videoPayload.rotation == 1) {
            self.videoTransform = "rotate(-90deg)";
          } else if (videoPayload.rotation == 2) {
            self.videoTransform = "rotate(180deg)";
          } else if (videoPayload.rotation == 3) {
            self.videoTransform = "rotate(90deg)";
          } else {
            self.videoTransform = "rotate(0deg)";
          }
        }
        self.displayVideoBox(videoMessageList[0].from);
      }
      // 发起人取消
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_SPONSOR_CANCEL) {
        if (self.formUser != "" && self.formUser != videoMessageList[0].from)
          return;
        // 隐藏接听界面
        self.changeState("isDialled", false, 7);
        if (!self.EndOfConsultationOrNot) {
          // self.$message({
          //     type: "info",
          //     message: "患者取消了视话问诊"
          // })
          self.$emit("changeVideoState", false);
        }
        self.$store.dispatch("GET_STATE", self.EndOfConsultationOrNot ? 5 : 3);

        self.VideoDisplay = false;
        self.VideoInterruption = true;
        if (self.ready) {
          self.ready = false;
          self.Trtc.leave();
        }
      }
      // 拒绝电话
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_REJECT) {
        // 隐藏接听界面
        self.changeState("dialling", false, 8);
      }
      // 无人接听
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_SPONSOR_TIMEOUT) {
        if (self.formUser != "" && self.formUser != videoMessageList[0].from)
          return;
        // 隐藏接听界面
        self.changeState("isDialled", false, 7);
        self.VideoInterruption = true;
        if (!self.EndOfConsultationOrNot) {
          self.$emit("changeVideoState", false);
        }
        self.$store.dispatch("GET_STATE", self.EndOfConsultationOrNot ? 5 : 3);
      }
      // 对方接听起自己发起的通话
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_ACCEPTED) {
        this.$bus.$emit("isAccept");
      }
      // 通话一段时间对方挂断
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_HANGUP) {
        if (self.formUser != "" && self.formUser != videoMessageList[0].from)
          return;
        self.VideoInterruption = true;
        self.isHungUp();
        let obj = {
          type: "info",
          message: ""
        };
        if (videoMessageList[0].from !== this.DoctorId) {
          // 显示接听界面
          obj.message = "对方断开了连接";
        } else {
          obj.message = "你已断开连接";
        }
        self.$message(obj);
      }
      // 电话占线 对方拒绝通话
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_LINE_BUSY) {
        // self.changeState('dialling', false, 10);
      }
      // 错误
      if (videoPayload.action === ACTION.VIDEO_CALL_ACTION_ERROR) {
        self.changeState("dialling", false, 11);
      }
    },

    // 监听事件   后期如果需要将融云im换成腾讯云需要把这个方法提到tim.js中
    initListener() {
      let self = this;

      // 收到离线消息和会话列表同步完毕通知，接入侧可以调用 sendMessage 等需要鉴权的接口
      tim.on(TIM.EVENT.SDK_READY, function(event) {
        // event.name - TIM.EVENT.SDK_READY
      });

      // 收到推送的单聊、群聊、群提示、群系统通知的新消息，可通过遍历 event.data 获取消息列表数据并渲染到页面
      tim.on(TIM.EVENT.MESSAGE_RECEIVED, function({ data: message, ...obj }) {
        // console.log(message);
        // console.log(obj);
        // if (self.$store.state.common.STATE == 2) return;
        self.handleVideoMessage(message);
        // event.name - TIM.EVENT.MESSAGE_RECEIVED
        // event.data - 存储 Message 对象的数组 - [Message]
      });

      // 收到 SDK 发生错误通知，可以获取错误码和错误信息
      tim.on(TIM.EVENT.ERROR, function(event) {
        console.log("被踢1111了", event);
        // console.log(event);
        // event.name - TIM.EVENT.ERROR
        // event.data.code - 错误码
        // event.data.message - 错误信息
      });

      // 收到 SDK 进入 not ready 状态通知，此时 SDK 无法正常工作
      tim.on(TIM.EVENT.SDK_NOT_READY, function(event) {
        // event.name - TIM.EVENT.SDK_NOT_READY
        //tim.login({ userID: 'user0', userSig: 'eJw1zEsKwjAUheG9ZKqUm-a2pgUXoBQn9qFDMWm4ijUmVaLi3g2tDs934H*zqtxGD2VZweII2HzcJFU-UEcj352y-8PJ88EYkqzgCJAgZhBPz0AXFTQVqchzzheTKm-IBs8ABcCvQTpUd816hWT3ba7rJ*qyw03vE2eur1l70wLjo29qqU6mgiX7fAHGwTFd' });
      });

      // 收到被踢下线通知
      tim.on(TIM.EVENT.KICKED_OUT, function(event) {
        console.log("被踢了", event);

        self.$emit("changeVideoState", false);
        self.$store.dispatch("GET_STATE", 2);
        // self.$store.dispatch("GET_TIMLOING_STATE", 6);
        // window.close();
        // 如果当前页面有数据就登回去如果没有就算了
        // event.name - TIM.EVENT.KICKED_OUT
        // event.data.type - 被踢下线的原因，例如:
        //    - TIM.TYPES.KICKED_OUT_MULT_ACCOUNT 多实例登录被踢
        //    - TIM.TYPES.KICKED_OUT_MULT_DEVICE 多终端登录被踢
        //    - TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED 签名过期被踢
        // 返回登录页
        self.basePushFun("/login?type=out");
        self.$store.dispatch("CHANGE_SET_SIG", "");
        self.$store.dispatch("GET_DOCTOR", null);
        self.$store.dispatch("GET_TIMLOING_STATE", null);
        localStorage.clear();
        sessionStorage.clear();
      });
    }
  },
  computed: {
    formatDurationStr() {
      return formatDuration(this.duration);
    }
  },
  destroyed() {}
};
</script>
<style  scoped>
.video_box {
  min-width: 550px;
  height: 100%;
  background: rgba(32, 32, 32, 1);
  border-radius: 6px;
  position: relative;
  overflow: hidden;
}
.videoCall_box {
  width: 100%;
  height: 100%;
  position: relative;
}
.videoCall_box .isRotacion {
  transform: rotate(-90deg);
  -ms-transform: rotate(-90deg); /* Internet Explorer */
  -moz-transform: rotate(-90deg); /* Firefox */
  -webkit-transform: rotate(-90deg); /* Safari 和 Chrome */
  -o-transform: rotate(-90deg); /* Opera */
}
.big {
  position: absolute;
  height: 100%;
  width: 100%;
}
.small {
  position: absolute;
  right: 20px;
  top: 10px;
  z-index: 9999;
  border: 1px solid #808080;
  height: 180px;
  width: 240px;
  border-radius: 5px;
  overflow: hidden;
}
.videoTips,
.videoTips_box {
  position: absolute;
  top: 300px;
  left: 50%;
  transform: translateX(-50%);
  color: #ffffff;
  font-size: 16px;
  font-weight: 500;
}
.videoTips_box {
  text-align: center;
  width: 450px;
}
.buttons {
  position: absolute;
  bottom: 50px;
  /* left: 50%; */
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transform: translateX(-50%);
  text-align: center;
  transform: translateZ(0px);
}
.buttons > p {
  color: white;
}
.buttons > i {
  width: 80px;
  height: 80px;
  display: block;
  border-radius: 50%;
  overflow: hidden;
  line-height: 80px;
  color: #ffffff;
  font-size: 45px;
  margin-bottom: 17px;
  cursor: pointer;
}
.Answer {
  background: linear-gradient(
    270deg,
    rgba(76, 218, 113, 1) 0%,
    rgba(57, 197, 93, 1) 100%
  );
}
.Answering {
  background: #ff5d5d;
}
.buttons > span {
  color: #c0c0c0;
  font-size: 14px;
}
</style>
